﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Storage;

namespace SaveTheQueen
{
    public class SpriteManager
    {
        #region StaticMembers
        private static Effect defautEffect;
        public static void LoadContents(ContentManager manager)
        {
            defautEffect = manager.Load<Effect>("Shaders/Defaut");
        }
        private static VertexPositionColorNormalTexture[] Quad()
        {
            // Quad Vertices
            Vector3 topLeftFront = new Vector3(0f, 1.0f, 0f);
            Vector3 bottomLeftFront = new Vector3(0f, 0f, 0f);
            Vector3 topRightFront = new Vector3(1.0f, 1.0f, 0f);
            Vector3 bottomRightFront = new Vector3(1.0f, 0f, 0f);

            // Normal
            Vector3 normal = Vector3.Backward;

            // Tex Coords
            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f);
            Vector2 textureBottomRight = new Vector2(1.0f, 1.0f);

            VertexPositionColorNormalTexture[] output = new VertexPositionColorNormalTexture[4];

            output[0] = new VertexPositionColorNormalTexture(topLeftFront, normal, textureTopLeft);
            output[1] = new VertexPositionColorNormalTexture(topRightFront, normal, textureTopRight);
            output[2] = new VertexPositionColorNormalTexture(topLeftFront, normal, textureBottomLeft);
            output[3] = new VertexPositionColorNormalTexture(bottomRightFront, normal, textureBottomRight);

            return output;
        }

        #endregion

        #region Fields
        GraphicsDevice device;
        List<TexturedRect> rects;

        Matrix viewMatrix;
        Matrix projectionMatrix;
        #endregion

        public SpriteManager(GraphicsDevice device)
        {
            this.device = device;
            this.viewMatrix = Matrix.CreateLookAt(Vector3.Backward, Vector3.Zero, Vector3.Down);
            this.projectionMatrix = Matrix.CreateOrthographicOffCenter
                (0, device.Viewport.Width, device.Viewport.Height, 0, 0, 1);

            rects = new List<TexturedRect>();
        }

        #region MainCode
        public void Begin()
        {
            rects.Clear();
            defautEffect.Parameters["MatrixTransform"].SetValue(viewMatrix * projectionMatrix);
            defautEffect.Parameters["ViewportSize"].SetValue(new Vector2(device.Viewport.Width, device.Viewport.Height));
        }

        public void DrawSprite(
            Texture2D tex, Vector2 position, Color tint, float rotation, Vector2 center,
            Vector2 scale, SpriteEffects effect, float depth, Effect shader, Matrix transform)
        {
            VertexPositionColorNormalTexture[] quad = Quad();
            quad[0].Position.Y = tex.Height;
            quad[2].Position.X = tex.Width;
            quad[2].Position.Y = tex.Height;
            quad[3].Position.X = tex.Width;
            Matrix fullTransform = Matrix.CreateRotationZ(MathHelper.ToRadians(-rotation)) * transform;

            for (int i = 0; i < quad.Length; i++)
            {
                //quad[1].Position.X *= tex.Width;
                //quad[1].Position.Y *= tex.Height;

                quad[i].Position -= new Vector3(center, 0);
                quad[i].Position *= new Vector3(scale, 0);

                quad[i].Position = Vector3.Transform(
                    quad[i].Position,
                    fullTransform);
                quad[i].Position += new Vector3(position, depth);

                quad[i].Color = tint;
            }

            rects.Add(new TexturedRect(quad, tex, new short[] { 1, 3, 2, 0, 1, 2 })); // crazy order, but it works ^^.
        }
        public void DrawString() { }

        public void End()
        {
            for (int i = 0; i < rects.Count; i++)
            {
                defautEffect.Parameters["sprite"].SetValue(rects[i].texture);
                defautEffect.Parameters["TextureSize"].SetValue(new Vector2(rects[i].texture.Width, rects[i].texture.Height));

                foreach (EffectPass p in defautEffect.CurrentTechnique.Passes)
                {
                    p.Apply();

                    device.DrawUserIndexedPrimitives<VertexPositionColorNormalTexture>(
                    PrimitiveType.TriangleList,
                    rects[i].rect,
                    0,
                    4,
                    rects[i].indexes,
                    0,
                    2);
                }
            }
        }
        #endregion

        #region Structs
        struct TexturedRect
        {
            public VertexPositionColorNormalTexture[] rect;
            public Texture2D texture;
            public short[] indexes;

            public TexturedRect(VertexPositionColorNormalTexture[] verts, Texture2D image, short[] vertIndexes)
            {
                rect = verts;
                texture = image;
                indexes = vertIndexes;
            }
        }
        struct VertexPositionColorNormalTexture : IVertexType
        {
            private static VertexDeclaration declaration = new VertexDeclaration(
                    new VertexElement[] { 
                    new VertexElement(0, VertexElementFormat.Vector3, VertexElementUsage.Position, 0),
                    new VertexElement(12, VertexElementFormat.Vector3, VertexElementUsage.Normal, 0) ,
                    new VertexElement(24, VertexElementFormat.Vector2, VertexElementUsage.TextureCoordinate, 0) ,
                    new VertexElement(32, VertexElementFormat.Color, VertexElementUsage.Color, 0) 
                });

            public Vector3 Position;
            public Vector3 Normal;
            public Vector2 TexCoords;
            public Color Color;

            public VertexPositionColorNormalTexture(Vector3 pos, Vector3 nor, Vector2 tcoords, Color col)
            {
                Position = pos;
                Normal = nor;
                TexCoords = tcoords;
                Color = col;
            }
            public VertexPositionColorNormalTexture(Vector3 pos, Vector3 nor, Vector2 tcoords)
            {
                Position = pos;
                Normal = nor;
                TexCoords = tcoords;
                Color = Color.White;
            }

            public VertexDeclaration VertexDeclaration
            {
                get { return declaration; }
            }
        }
        #endregion
    }
}
